use anchor_lang::prelude::*;

use anchor_lang::solana_program::{
    account_info::{next_account_info, AccountInfo},
    entrypoint,
    entrypoint::ProgramResult,
    instruction::{AccountMeta, Instruction},
    program::invoke,
    pubkey::Pubkey,
};

declare_id!("HSGnGfoEdLa9fwNobnp3KXs22J1sQzzBXrdUicmkHSXD");


#[repr(C)]
#[derive(AnchorSerialize, AnchorDeserialize, Clone)]
pub struct OutBoundParams {
    pub network_id:u128,
    pub contract_address: Vec<u8>, 
    pub functionCallData: Vec<u8>, 
    pub source_contract_address: [u8;32]

}

const SIGHASH_GLOBAL_NAMESPACE : &str= "global";

/// The function discrminator is constructed from these 8 bytes. Typically, the namespace is
/// "global" or "state"
pub fn ix_discriminator(name: &str) -> [u8; 8]{
    let preimage = format!("{}:{}", SIGHASH_GLOBAL_NAMESPACE, name);
    let mut sighash = [0u8; 8];
    sighash.copy_from_slice(
        &anchor_lang::solana_program::hash::hash(preimage.as_bytes()).to_bytes()[..8],
    );
    sighash
}

#[program]
pub mod cpiapp {
    use super::*;

    pub fn initialize(ctx: Context<Initialize>) -> Result<()> {
        msg!("Greetings from: {:?}", ctx.program_id);
        Ok(())
    }
    pub fn wmb_receive(ctx: Context<WmbReceiveAccount>, data: Vec<u8>) -> Result<()> {
        msg!("Greetings from: {:?},data: {:?}", ctx.program_id, data);
        Ok(())
    }
    pub fn callOutbound(ctx: Context<OutBoundAccounts>, network_id:u128, contract_address: Vec<u8>, functionCallData:Vec<u8>) -> Result<()> {
        msg!("Greetings from: {:?}", ctx.program_id);
        
        let source_contract_address = ctx.program_id.to_bytes();
        
        let params = OutBoundParams{
            network_id,
            contract_address,
            functionCallData,
            source_contract_address
        };

        let mut ix_data = Vec::new();
        let r1 = ix_discriminator("outbound_call");//outbound_call
        let r2 = params.try_to_vec().unwrap();

        ix_data.extend_from_slice(&r1);
        ix_data.extend_from_slice(&r2);
        let accounts_meta = vec![
            
        ];
        let ix = &Instruction::new_with_bytes(
            ctx.accounts.message_gate_program.key(),
            &ix_data,
            accounts_meta,
        );
        let account_infos = vec![];
        invoke(ix, &account_infos)?;
        Ok(())
        
        
    }
}

#[derive(Accounts)]
pub struct Initialize {}



#[derive(Accounts)]
pub struct WmbReceiveAccount {}


#[derive(Accounts)]
pub struct OutBoundAccounts<'info> {
    /// CHECK: This account is neither written to nor read from.
    pub message_gate_program:UncheckedAccount<'info>
}